/*
 * FixedSizeBlockFile.h
 *
 *  Created on: Oct 10, 2012
 *      Author: m
 */

#ifndef FIXEDSIZEBLOCKFILE_H_
#define FIXEDSIZEBLOCKFILE_H_

#include <iostream>
#include <fstream>
#include "physical_layer_commons.h"

namespace physical
{

/**
 * Archivo de bloques de tamaño fijo
 *
 * Permite Acceso aleatorio a bloques
 */
class FixedSizeBlockFile
{
public:

	/**
	 * Constructor
	 *
	 * Si no se indica "filename" ni "openmode", no se asocia ningún
	 *  archivo físico al BlockFile. Si solo se indica el filename
	 *  se asocia dicho archivo al BlockFile y se lo abre en el modo
	 *  por defecto ( in | out ). Si se indican todos los parámetros
	 *  se abre el archivo "filename" en el modo "openmode" indicado.
	 *
	 * @param blockSize Tamaño de bloque
	 * @param filename  Nombre del archivo de bloques (opcional)
	 * @param mode      Modo de apertura del archivo (opcional)
	 */
	FixedSizeBlockFile( size_t blockSize, const char filename[] = NULL, openmode  mode = defaulOpenmode );

	/**
	 * Destructor
	 */
	virtual ~FixedSizeBlockFile();

	/**
	 * Método para leer bloques del archivo
	 *
	 * @param position Posición del bloque a leer
	 * @param buffer   Array de bytes donde se guardará el bloque leido
	 */
	void readBlock( blockNumber position, byteStream buffer );

	/**
	 * Método para escribir bloques
	 *
	 * Si el bloque a escribir ya existe se sobre-escribe, sino se
	 *  expande el archivo lo que sea necesario y se escribe un
	 *  nuevo bloque
	 *
	 * @param position Posición del bloque a leer
	 * @param buffer   Array de Bytes a escribir en el archivo
	 */
	void writeBlock( blockNumber position, const byteStream buffer );

	/**
	 * Devuelve el tamaño de bloque del archivo
	 *
	 * TODO: REVISAR ESTO!
     *
     * @warning Will probably be DEPRECATED in future versions
	 *
	 * @return El tamaño de bloque del archivo
	 */
	size_t getBlockSize() const;

	/**
	 * Devuelve el tamaño en bytes del archivo de bloques
	 *
	 * TODO: REVISAR ESTO!
     *
     * @warning Will be DEPRECATED in future versions
	 *
	 * @return El tamaño en bytes del archivo
	 */
	size_t getFileSize() const; // TODO: revisar para que sirve tener esto...

	/**
	 * Devuelve la cantidad de bytes leidos/escritos por la
	 *  última operación realizada sobre el archivo
	 *
     * TODO: REVISAR ESTO!
     *
     * @warning Will be DEPRECATED in future versions
	 *
	 * @return Cantidad de bytes escritos/leidos por la última operación
	 */
	size_t gcount() const;  // TODO: revisar para que sirve tener esto!

	/**
	 * Devuelve la cantidad total de bloques en el archivo
	 *
	 * @return La cantidad total de bloques ene l archivo
	 */
	size_t getBlocksCount() const;

	/**
	 * Verifica si se ha llegado al final del archivo
	 *
	 * TODO: Sacar esto!
	 *
	 * @warning DEPRECATED!
	 *
	 * @return true si se alcanzo eof, false en caso contrario
	 */
	bool eof() const;

	/**
	 * Abre un archivo de bloques
	 *
     * @param filename  Nombre del archivo de bloques
     * @param mode (opcional) Modo de apertura del archivo, ( in | out ) por defecto
	 */
	void open( const char filename[], openmode mode = defaulOpenmode );

	/**
	 *  Cierra el archivo de bloques
	 */
	void close();

	/**
	 * Permite modificar el tamaño de bloque del archivo
	 *
	 * TODO: Sacar esto!
	 *
	 * @warning DEPRECATED!
	 *
	 * @param blockSize
	 */
	void resetBlockSize( size_t blockSize ); // TODO: revisar si es realmente necesario

protected:
    std::fstream m_blockSource; /// fstream al archivo de bloques
    size_t m_blockSize;         /// El tamaño de bloque
    static const openmode defaulOpenmode;   /// Modo de apertura por defecto
	void readBlock( byteStream buffer );
	void writeBlock( const byteStream buffer );
};

/*************************************************************
 **********************   Exepciones   **********************
 *************************************************************/

/**
 * Excepción Genérica de FixedSizeBlockFile
 */
class FixedSizeBlockFileException : public PhysicalException
{
};

/**
 * Excepción: Intentando realizar operación I/O en BlockFile con
 *  tamaño cero o menor
 */
class InvalidBlockSizeException: public FixedSizeBlockFileException
{
  virtual const char* what() const throw()
  {
    return "Trying I/O Operation from Block File with block size 0 or lower.";
  }
};

}
#endif /* FIXEDSIZEBLOCKFILE_H_ */
